package genetic.q1;

import java.math.BigDecimal;
import java.util.List;

import genetic.Genotype;
import genetic.Phenotype;

public class AckleyPhenotype extends Phenotype{

	@Override
	public Genotype createRandomInstance() {
		return new AckleyGenotype(getRandomBitString(48, 0.5));
//		double b1 = round(((int)(Math.random()*65535)-32767)/1000.0, 3);
//		double b2 = round(((int)(Math.random()*65535)-32767)/1000.0, 3);
//		double b3 = round(((int)(Math.random()*65535)-32767)/1000.0, 3);
//		return new AckleyGenotype(new double[]{b1, b2, b3});
	}

	@Override
	public Genotype[] crossover(Genotype g1, Genotype g2) {
		boolean[][] offsprings = singlePointCrossOver(g1.getBitString(), g2.getBitString());
		return new Genotype[]{new AckleyGenotype(offsprings[0]), new AckleyGenotype(offsprings[1])};
	}

	@Override
	public double fitness(Genotype g) {
		return 20+Math.E-computeFunctionValue(g);
	}

	public static double computeFunctionValue(Genotype g){
		AckleyGenotype ge = (AckleyGenotype)g;
		double[] vals = ge.getVal();
		double sum1 = vals[0]*vals[0] + vals[1]*vals[1] + vals[2]*vals[2];
		double sum2 = Math.cos(Math.PI*2*vals[0]) + Math.cos(Math.PI*2*vals[1]) + Math.cos(Math.PI*2*vals[2]);
		double res = (-20.0*Math.exp(-0.2*Math.sqrt(sum1/3.0)) - Math.exp(sum2/3.0) + 20.0 + Math.E);
		return res;
	}

	@Override
	public Genotype mutate(Genotype g, double Pm) {
		//bitwise mutation
		boolean[] rep = g.getBitString();
		return new AckleyGenotype(bitwiseMutation(rep, Pm));
	}

	public static double round(double d, int decimalPlace){
		BigDecimal bd = new BigDecimal(Double.toString(d));
		bd = bd.setScale(decimalPlace,BigDecimal.ROUND_HALF_UP);
		return bd.doubleValue();
	}

	@Override
	public List<Genotype> getMatingPool(List<Genotype> population, int populationSize) {
		return getMatingPoolRouletteWheel(population, populationSize);
	}

}
